#include "SceneRendering.h"
#include "RenderGraphResource.h"
#include "Shader.h"
#include "Runtime/Engine/Material.h"
#include "Runtime/Log/Logger.h"
#include "Runtime/Logic/MeshDescription/MeshDescription.h"
#include "Runtime/Logic/Resource/StaticMesh.h"
#include "Runtime/CGI/PipelineStateCache.h"
#include "Runtime/Logic/World.h"
#include "Runtime/Resources/ShaderCode.h"
#include "Runtime/Thread/RenderingThreadContext.h"

namespace Alice
{
    static StaticMesh*sStaticMesh=nullptr;
    static Material*sMaterial=nullptr;
    static VertexShader* sVertexShader=nullptr;
    static PixelShader* sPixelShader=nullptr;
    ViewFamilyInfo::ViewFamilyInfo(const SceneViewFamily& InViewFamily)
        :SceneViewFamily(InViewFamily)
    {
        
    }


    IRendererModule* CachedRendererModule = NULL;
    IRendererModule* GetRendererModule()
    {
        if (!CachedRendererModule)
        {
            CachedRendererModule = new RendererModule;
        }

        return CachedRendererModule;
    }
    RendererModule::RendererModule()
    {
        
    }
    /*CGITexture* TryCreateViewFamilyTexture(RDGBuilder& GraphBuilder, const SceneViewFamily& ViewFamily)
    {
        const CGITexture* cgiTexture = ViewFamily.mRenderTarget->GetRenderTargetTexture();
        CGITexture* Texture = nullptr;
        if (cgiTexture)
        {
            Texture = RegisterExternalTexture(GraphBuilder, cgiTexture, TEXT("ViewFamilyTexture"));
            GraphBuilder.SetTextureAccessFinal(Texture, ECGIAccess::RTV);
        }
        return Texture;
    }

    CGITexture* TryCreateViewFamilyDepthTexture(RDGBuilder& GraphBuilder, const SceneViewFamily& ViewFamily)
    {
        if (!ViewFamily.mRenderTargetDepth)
        {
            return nullptr;
        }
        //CGITexture* TextureRHI = ViewFamily.mRenderTargetDepth->GetRenderTargetTexture();
        CGITexture* Texture = nullptr;
        //if (TextureRHI)
        {
            //Texture = RegisterExternalTexture(GraphBuilder, TextureRHI, TEXT("ViewFamilyDepthTexture"));
            //GraphBuilder.SetTextureAccessFinal(Texture, ECGIAccess::DSVWrite);
        }
        return Texture;
    }*/
    void RendererModule::BeginRenderingViewFamily(SceneViewFamily* inSceneViewFamily)
    {
        World*world=inSceneViewFamily->Scene->GetWorld();
        world->SendAllEndOfFrameUpdates();
        SceneRenderer*sceneRenderer=new DeferredShadingRenderer(inSceneViewFamily);
        ENQUEUE_RENDER_COMMAND(BeginRenderViewFamily)([sceneRenderer](CGICommandListImmediate&inCGICommandList)
        {
            RDGBuilder rdgBuilder(inCGICommandList);
            sceneRenderer->Render(rdgBuilder);
            rdgBuilder.Execute();
            delete sceneRenderer;
        });
    }
    IVisibilityTaskData* LaunchVisibilityTasks(CGICommandListImmediate& inCGICommandList, SceneRenderer& inSceneRenderer,const FTask& inBeginInitVisibilityPrerequisites)
    {
        FVisibilityTaskData* TaskData = new FVisibilityTaskData(&inCGICommandList,&inSceneRenderer);// SceneRenderer.Allocator.Create<FVisibilityTaskData>(RHICmdList, SceneRenderer);
        TaskData->LaunchVisibilityTasks(inBeginInitVisibilityPrerequisites);
        return TaskData;
    }
    SceneRenderer::SceneRenderer(const SceneViewFamily* inSceneViewFamily)
        :mViewFamilyInfo(*inSceneViewFamily),Scene(inSceneViewFamily->Scene->GetRenderScene())
    {
        
    }
    IVisibilityTaskData* SceneRenderer::OnRenderBegin(RDGBuilder& GraphBuilder)
    {
        IVisibilityTaskData* visibilityTaskData = nullptr;
        FUpdateParameters updateParameters;
        updateParameters.mPostStaticMeshUpdate=[&](const FTask& inStaticMeshUpdateTask)
        {
            visibilityTaskData=LaunchVisibilityTasks(*GraphBuilder.mCGICommandList,*this,inStaticMeshUpdateTask);
        };
        Scene->Update(GraphBuilder,updateParameters);
        return visibilityTaskData;
    }
    void SceneRenderer::SetupMeshPass(ViewInfo& inViewInfo, FViewCommands& ViewCommands)
    {
        
    }
    DeferredShadingRenderer::DeferredShadingRenderer(const SceneViewFamily* inSceneViewFamily)
        :SceneRenderer(inSceneViewFamily)
    {
        
    }
    void DeferredShadingRenderer::Render(RDGBuilder& GraphBuilder)
    {
        FInitViewTaskDatas initViewTaskDatas=OnRenderBegin(GraphBuilder);
        RDGTexture*colorRT=new RDGTexture();
        colorRT->mCGIResource=mViewFamilyInfo.mRenderTarget->GetRenderTargetTexture();
        std::vector<TextureRenderTargetBinding> basePassTextures;
        basePassTextures.push_back(TextureRenderTargetBinding(colorRT));
        RenderTargetBindingSlots BasePassRenderTargets = GetRenderTargetBindings(ERenderTargetLoadAction::EClear, basePassTextures);
        BasePassParameter*passParameter=new BasePassParameter;
        passParameter->mRenderTargetBindingSlots=BasePassRenderTargets;
        BeginInitViews(GraphBuilder,initViewTaskDatas);
        EndInitViews(GraphBuilder,initViewTaskDatas);
        GraphBuilder.AddDispatchPass(passParameter,ERDGPassFlags::Raster,[](RDGDispatchPassBuilder& DispatchPassBuilder)
        {
            CGICommandList* RHICmdList = DispatchPassBuilder.CreateCommandList();
            //Debug("Render Execute Dispatch Pass");
            if(sStaticMesh==nullptr)
            {
                /*sStaticMesh=new StaticMesh;
                sStaticMesh->Build();
                sMaterial=new Material;
                sMaterial->CacheResourceShadersForRendering();
                sVertexShader=Shader::GetOrCreateShaderFromShaderPath<VertexShader>(EMeshPass::BasePass,"Res/test.vsb"); //CGICreateVertexShader("Res/test.vsb",vsCode.mData.mData,vsCode.mData.mDataLen);
                sPixelShader=Shader::GetOrCreateShaderFromShaderPath<PixelShader>(EMeshPass::BasePass,"Res/test.fsb");//CGICreatePixelShader("Res/test.fsb",fsCode.mData.mData,fsCode.mData.mDataLen);*/
            } else {
                FGraphicsPipelineStateInitializer PSInitializer;
                PSInitializer.RenderTargetsEnabled=1;
                PSInitializer.RenderTargetFormats.resize(1);
                PSInitializer.RenderTargetFormats[0]=EPixelFormat::PF_B8G8R8A8;
                PSInitializer.RenderTargetFlags.push_back(ETextureCreateFlags::RenderTargetable|ETextureCreateFlags::Presentable);
                PSInitializer.mBoundShaderStateInput.mVertexShader=reinterpret_cast<CGIVertexShader*>(sVertexShader->mCGIShader);
                PSInitializer.mBoundShaderStateInput.mPixelShader=reinterpret_cast<CGIPixelShader*>(sPixelShader->mCGIShader);
                SetGraphicsPipelineState(*RHICmdList,PSInitializer,0,EApplyRendertargetOption::DoNothing,false);
                RHICmdList->GetContext().RHISetStreamSource(0,sStaticMesh->mStaticMeshResource->mStaticMeshLODResource->mMeshVertexBuffers->mPositionBuffer->mCGIBuffer,0);
                RHICmdList->GetContext().RHIDrawPrimitive(0,3,1);
            }
            RHICmdList->EndRenderPass();
        });
    }
    void DeferredShadingRenderer::BeginInitViews(RDGBuilder& GraphBuilder,FInitViewTaskDatas&inVisibilityTaskData)
    {
        //inVisibilityTaskData.mVisibilityTaskData->ProcessRenderThreadTasks();
    }
    void DeferredShadingRenderer::EndInitViews(RDGBuilder& GraphBuilder,FInitViewTaskDatas&inVisibilityTaskData)
    {
        
    }

}
